/*----------------------------------------------------------------------------*/
/* Copyright 2020-2021 NXP                                                    */
/*                                                                            */
/* NXP Confidential. This software is owned or controlled by NXP and may only */
/* be used strictly in accordance with the applicable license terms.          */
/* By expressly accepting such terms or by downloading, installing,           */
/* activating and/or otherwise using the software, you are agreeing that you  */
/* have read, and that you agree to comply with and are bound by, such        */
/* license terms. If you do not agree to be bound by the applicable license   */
/* terms, then you may not retain, install, activate or otherwise use the     */
/* software.                                                                  */
/*----------------------------------------------------------------------------*/

/** \file
*
* Example Source for NfcrdlibEx10_MIFAREDESFire_EVx that demonstrates communication
* with MIFARE DESFire EV2 contactless IC and MIFARE DESFire EV3 contactless IC cards.
* This example will Detect and activater the Type-A card.
* If card is MIFAREDESFire EV2 and MIFAREDESFire EV3 then it will format the card and create application
* After creating application, it will create one Standard File. It will
* demo read and write operations with the card.
* KEYTYPE is AES.
* Please refer Readme.txt file for Hardware Pin Configuration, Software Configuration and steps to build and
* execute the project which is present in the same project directory.
*
* $Author$
* $Revision$ (v07.02.00)
* $Date$
*
*/

/**
* Reader Library Headers
*/
#include <phApp_Init.h>
#include "BSP.h"
#include "log/log2.h"
#include <Utility.h>

#include <Reader/Reader.h>
#include "phpalCt/phpalCt.h"
#include "phalMfdfEVx.h"
#include "config/config3.h"
#include "reader_samav3.h"
#include "ISO7816/i7816.h"

/* *****************************************************************************************************************
* MACROS/Defines
* ***************************************************************************************************************** */

#define AES128_KEY_ADDRESS       0       /* PICC Key entry number in key store. */
#define AES128_KEY_VERSION       0       /* PICC Key entry number in key store. */


#define SAM_MASTER_KEY			 0
#define SAM_MASTER_KEY_VERSION	 0

#define PH_EXCT7816_MAX_ATR_SIZE         33

#define APPLE_KEY_ID_DES			0x21
#define APPLE_KEY_ID_AES			0x22

#define GOOGLE_KEY_ID_AES			0x23

#define SAM_AV3_GET_VERSION_STATE					30
#define SAM_AV3_GET_VERSION_STATE_UNACTIVATED		0x03

#define SAM_AV3_GET_VERSION_UID						14
#define SAM_AV3_GET_VERSION_UID_LEN  				7

/*******************************************************************************
**   Global Variable Declaration
*******************************************************************************/


phhalHw_SamAV3_DataParams_t stHal_SamAv3;
/** Instance for  CT pal parameter's structure */

static uint8_t aTx_SamBuffer[260];
static uint8_t aRx_SamBuffer[260];

/* AES default key */
static uint8_t aAES128Key[16] = {
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};

static uint8_t samav3_uid[SAM_AV3_GET_VERSION_UID_LEN];
static uint8_t samav3_ready = 0;
static uint8_t samav3_state = 0; // 0 - 未激活，1 - 已激活
/*===================================================================================*/

/*===================================================================================*/


/*==============================================================================================================*/
/* *****************************************************************************************************************
* Types/Structure Declarations
* ***************************************************************************************************************** */

/* *****************************************************************************************************************
* Function Prototypes
* ***************************************************************************************************************** */

/*******************************************************************************
**   Function Definitions
*******************************************************************************/
static phStatus_t key_store_init(phKeyStore_Sw_DataParams_t * pKeyStore)
{
    phStatus_t status;

    status = phKeyStore_FormatKeyEntry(pKeyStore, AES128_KEY_ADDRESS, PH_CRYPTOSYM_KEY_TYPE_AES128);
    CHECK_SUCCESS(status);

    return phKeyStore_SetKeyAtPos(pKeyStore, AES128_KEY_ADDRESS, 0x00, PH_CRYPTOSYM_KEY_TYPE_AES128,
            aAES128Key, AES128_KEY_VERSION);
}

static int key_store_set_master_key(uint8_t master_key[16]){

	phKeyStore_Sw_DataParams_t * pKeyStore = phNfcLib_GetDataParams(PH_COMP_KEYSTORE);
    phStatus_t status;

    status = phKeyStore_FormatKeyEntry(pKeyStore, AES128_KEY_ADDRESS, PH_CRYPTOSYM_KEY_TYPE_AES128);
    CHECK_SUCCESS(status);

    return phKeyStore_SetKeyAtPos(pKeyStore, AES128_KEY_ADDRESS, 0x00, PH_CRYPTOSYM_KEY_TYPE_AES128,
            master_key, AES128_KEY_VERSION);
}

int samav3_init(void){
	phKeyStore_Sw_DataParams_t * pKeyStore = phNfcLib_GetDataParams(PH_COMP_KEYSTORE);
	key_store_init(pKeyStore);
	return phpalCt_Init();
}


int samav3_deactivate(void){
	if(!samav3_state){
		return 0;
	}
	samav3_state = 0;
	return phpalCt_DeInit();
}

int samav3_activate(void){
    phStatus_t  status = 0;
    uint16_t    wTechDetected = 0;
    uint8_t     bTagType;
    uint8_t     bCardRemoved = 0U;

    /** Instance for  CT pal parameter's structure */
	phpalCt_DataParams_t pDataParams ;
	
	// phpalCt_Init();
    /** Check the card presence */
    // DEBUG_PRINTF("Waiting for CT card insertion.\n");

	// DEBUG_PRINTF("CT card detected\n");

    /* The response buffer is used to optimize the code */
	pDataParams.pbAtrBuffer = (uint8_t *)(&aRx_SamBuffer);
	pDataParams.bSizeOfATRbuffer = PH_EXCT7816_MAX_ATR_SIZE;

	/* Activate the card */
	status = phpalCt_ActivateCard(&pDataParams);
	if(PH_ERR_SUCCESS != status)
	{
		DEBUG_PRINTF("Card Activation failed.\n");
		DEBUG_ERROR_PRINT(status);
	}

	/* Initialize library */
	 /* Set the generic pointer */
	void* pHal = phNfcLib_GetDataParams(PH_COMP_HAL);
	void *pKeyStore = phNfcLib_GetDataParams(PH_COMP_KEYSTORE);
	void * pCryptoENC = phNfcLib_GetDataParams_Extended(PH_COMP_CRYPTOSYM, PH_NFCLIB_COMP_CRYPTOSYM_TYPE_ENC);
	void * pCryptoMAC = phNfcLib_GetDataParams_Extended(PH_COMP_CRYPTOSYM, PH_NFCLIB_COMP_CRYPTOSYM_TYPE_MAC);
	void * pCryptoRng = phNfcLib_GetDataParams(PH_COMP_CRYPTORNG);
	
	 /* Init SAM AV3 */
	 status = phhalHw_SamAV3_Init(
		&stHal_SamAv3,
		sizeof ( stHal_SamAv3 ),
		&pDataParams, //?phpalCt_DataParams_t pDataParams <-- isnt this a pal, not bal?
		pHal,
		pKeyStore,
		pCryptoENC,
		pCryptoMAC,
		pCryptoRng,
		NULL,
		NULL,
		PHHAL_HW_SAMAV3_OPMODE_NON_X,
		0x00,
		aTx_SamBuffer,
		sizeof ( aTx_SamBuffer ),
		aRx_SamBuffer,
		sizeof ( aRx_SamBuffer ),
		NULL
		);


	 if(status == PH_ERR_SUCCESS) {
		 DEBUG_PRINTF("\n SAM Init successful!");
	 }
	 else {
		DEBUG_PRINTF("\n SAM Init failed!");
		DEBUG_ERROR_PRINT(status);
	}

    /* SAM Get Version */
    uint8_t rxLen = 0;
    status = phhalHw_SamAV3_Cmd_SAM_GetVersion(
    		&stHal_SamAv3,
			aRx_SamBuffer,
			&rxLen);

    if(status != PH_ERR_SUCCESS) {
		DEBUG_PRINTF("\n SAM GetVersion failed!");
		DEBUG_ERROR_PRINT(status);
    }
    else{
    	 /* Print SAM Version */
    	DEBUG_PRINTF("\nSAM AV3 Get Version: ");
    	LOG2_BUF_INF("\t", aRx_SamBuffer, rxLen);
    }
	
	
	if(aRx_SamBuffer[SAM_AV3_GET_VERSION_STATE] == SAM_AV3_GET_VERSION_STATE_UNACTIVATED) {
		/* Activate SAM AV3 if not yet done */
		DEBUG_PRINTF("\nSAM LockUnlock: ");
		status = phhalHw_SamAV3_Cmd_SAM_LockUnlock(
				&stHal_SamAv3,
				PHHAL_HW_SAMAV3_CMD_SAM_LOCK_UNLOCK_TYPE_ACTIVATE_SAM,
				AES128_KEY_ADDRESS,
				AES128_KEY_VERSION,
				SAM_MASTER_KEY,
				SAM_MASTER_KEY_VERSION,
				0,
				0,
				0
		);
	}

	/* Perform HostAuth with SAM Master Key. */
	DEBUG_PRINTF("\nSAM Host Authentication: ");
#if 0
	status = phhalHw_SamAV3_Cmd_SAM_AuthenticateHost(
			&stHal_SamAv3,
			PHHAL_HW_SAMAV3_CMD_SAM_AUTHENTICATE_HOST_MODE_PLAIN,
			AES128_KEY_ADDRESS,
			AES128_KEY_VERSION,
			SAM_MASTER_KEY,
			SAM_MASTER_KEY_VERSION
	);
#endif 
	status = phhalHw_SamAV3_Cmd_SAM_AuthenticateHost(
			&stHal_SamAv3,
			PHHAL_HW_SAMAV3_CMD_SAM_AUTHENTICATE_HOST_MODE_FULL,
			AES128_KEY_ADDRESS,
			AES128_KEY_VERSION,
			SAM_MASTER_KEY,
			SAM_MASTER_KEY_VERSION
	);

	if(status != PH_ERR_SUCCESS) {
		DEBUG_PRINTF(" failed!");
		DEBUG_ERROR_PRINT(status);
	}
	else {
		DEBUG_PRINTF(" successful!");
	}
	return status;
}

//分散密钥后，检测mac
int samav3_verify_mac_div(uint8_t kid, uint8_t key_ver, uint8_t* div, uint8_t div_len, uint8_t* data, uint16_t dlen){

	phStatus_t status;
	PH_CHECK_SUCCESS_FCT(status, phhalHw_SamAV3_Cmd_SAM_ActivateOfflineKey(
		&stHal_SamAv3,
		PHHAL_HW_SAMAV3_CMD_SAM_AO_LRP_UPDATE_KEY_RFU,
		kid,
		key_ver,
		div,
		div_len));

	PH_CHECK_SUCCESS_FCT(status, phhalHw_SamAV3_Cmd_SAM_VerifyMAC(
		&stHal_SamAv3,
		PH_EXCHANGE_DEFAULT,
		0x08,
		data,
		dlen));
	return 0;
}


//读取samav3密钥
int samav3_get_key_entry(uint8_t kid, key_entry_read_t *key_entry){
    phStatus_t status = 0;
    uint8_t bRxBuffer[0x40];  // SAM key entry data buffer
    uint8_t bRxLength = 0;    // 返回数据长度
    
    status = phhalHw_SamAV3_Cmd_SAM_GetKeyEntry(
        &stHal_SamAv3,
        kid,
		PHHAL_HW_SAMAV3_CMD_SAM_GET_KEY_ENTRY_KEY_ENTRY_NEW,
        bRxBuffer,
        &bRxLength
    );
    
    if(status == PH_ERR_SUCCESS) {
        memcpy(key_entry, bRxBuffer, bRxLength);
    }
    
    return status;
}

//装载samav3密钥
int samav3_change_key_entry(uint8_t kid, sam_key_entry_t *key_entry){
	return phhalHw_SamAV3_Cmd_SAM_ChangeKeyEntry(&stHal_SamAv3, kid, 0xFF, (uint8_t*)key_entry, 0x40);
}

int samav3_disable_key_entry(uint8_t kid){
	phStatus_t  status;
	key_entry_read_t key_entry_read;
	status = samav3_get_key_entry(kid, &key_entry_read);
	if(status != PH_ERR_SUCCESS){
		LOG2_ERR("samav3_get_key_entry fail: %04X", status);
		return -1;
	}
	if(key_entry_read.set & 0x0200){
		//已经禁用
		return 0;
	}
	sam_key_entry_t key_entry;

	memset(&key_entry, 0, sizeof(key_entry));
	key_entry.kuc_no = 0xFF;	
	key_entry.kae_no = 0xFE;
	key_entry.kae_ver = 0xFF;
	key_entry.set = 0x0020;	
	status = phhalHw_SamAV3_Cmd_SAM_ChangeKeyEntry(&stHal_SamAv3, kid, 0xFF, (uint8_t*)&key_entry, 0x40);
	if(status != PH_ERR_SUCCESS){
		LOG2_ERR("phhalHw_SamAV3_Cmd_SAM_ChangeKeyEntry fail: %04X", status);
		return -1;
	}
	status = phhalHw_SamAV3_Cmd_SAM_DisableKeyEntry(&stHal_SamAv3, kid, NULL, 0);
	return status;	
}

int samav3_load_key(uint8_t kid, const uint8_t key[16], uint8_t kver, uint8_t kclass, uint8_t ktype, uint8_t keep_iv){
	phStatus_t  status;
	sam_key_entry_t key_entry;

	memset(&key_entry, 0, sizeof(key_entry));
	memcpy(key_entry.keys[0], key, 16);
	key_entry.key_ver[0] = kver;
	key_entry.set = (ktype << 3) | (keep_iv << 2);
	key_entry.ext_set = kclass;
	key_entry.kuc_no = 0xFF;

	status = phhalHw_SamAV3_Cmd_SAM_ChangeKeyEntry(&stHal_SamAv3, kid, 0xFF, (uint8_t*)&key_entry, 0x40);
	return status;	
}

int samav3_load_key_if_changed(uint8_t kid, const uint8_t key[16], uint8_t kver, uint8_t kclass, uint8_t ktype, uint8_t keep_iv){
	phStatus_t  status;
	key_entry_read_t key_entry_read;
	
	status = samav3_get_key_entry(kid, &key_entry_read);
	if(status != PH_ERR_SUCCESS){
		LOG2_ERR("samav3_get_key_entry fail: %04X", status);
		return -1;
	}
	
	if(key_entry_read.ver[0] != kver || key_entry_read.ext_set != kclass || key_entry_read.set != ((ktype << 3) | (keep_iv << 2))){
		status = samav3_load_key(kid, key, kver, kclass, ktype, keep_iv);
		if(status != PH_ERR_SUCCESS){
			LOG2_ERR("reader_samav3_load_key fail: %04X", status);
			return -2;
		}
		return 1;
	}

	return 0;
}


int samav3_load_default_key(uint8_t kid, const uint8_t key[16], uint8_t kver, uint8_t kclass, uint8_t ktype, uint8_t keep_iv){
	phStatus_t  status;
	key_entry_read_t key_entry_read;
	
	status = samav3_get_key_entry(kid, &key_entry_read);
	if(status != PH_ERR_SUCCESS){
		LOG2_ERR("samav3_get_key_entry fail: %04X", status);
		return -1;
	}
	
	if(key_entry_read.ver[0] == 0){
		status = samav3_load_key(kid, key, kver, kclass, ktype, keep_iv);
		if(status != PH_ERR_SUCCESS){
			LOG2_ERR("reader_samav3_load_key fail: %04X", status);
			return -2;
		}
		return 1;
	}

	return 0;
}


static int samav3_generate_master_key(uint8_t *div, uint8_t dlen, uint8_t *key){
	uint8_t master_key_root[16] = {0xC4,0x07,0xAB,0xE5,0x03,0x61,0xB1,0x9B,0x21,0x34,0xDD,0x30,0xB1,0xF5,0xEC,0x5C};
	phStatus_t status;
	void* pCrypto = phNfcLib_GetDataParams_Extended(PH_COMP_CRYPTOSYM, PH_NFCLIB_COMP_CRYPTOSYM_TYPE_DIVERSIFY);
	status = phCryptoSym_DiversifyDirectKey(
		pCrypto,
		PHAL_MFDFEVX_DIV_METHOD_CMAC,
		master_key_root,
		PH_KEYSTORE_KEY_TYPE_AES128,
		div,
		dlen,
		key
		);
	return status;
}


int samav3_activate2(void){
	if(samav3_ready == 0){
		return -1;
	}
	if(samav3_state == 1){
		if(i7816_is_activated(0)){
			return 0;
		}
		samav3_state = 0;
	}
    phStatus_t status;
	
    /** Instance for  CT pal parameter's structure */
	phpalCt_DataParams_t palCt_DataParams ;
    /* The response buffer is used to optimize the code */
	palCt_DataParams.pbAtrBuffer = (uint8_t *)(&aRx_SamBuffer);
	palCt_DataParams.bSizeOfATRbuffer = PH_EXCT7816_MAX_ATR_SIZE;

	/* Activate the card */
	status = phpalCt_ActivateCard(&palCt_DataParams);
	if(PH_ERR_SUCCESS != status){
		LOG2_ERR("Ct Activation fail: %d", status);
		return status;
	}

	/* Initialize library */
	 /* Set the generic pointer */
	void* pHal = phNfcLib_GetDataParams(PH_COMP_HAL);
	void *pKeyStore = phNfcLib_GetDataParams(PH_COMP_KEYSTORE);
	void * pCryptoENC = phNfcLib_GetDataParams_Extended(PH_COMP_CRYPTOSYM, PH_NFCLIB_COMP_CRYPTOSYM_TYPE_ENC);
	void * pCryptoMAC = phNfcLib_GetDataParams_Extended(PH_COMP_CRYPTOSYM, PH_NFCLIB_COMP_CRYPTOSYM_TYPE_MAC);
	void * pCryptoRng = phNfcLib_GetDataParams(PH_COMP_CRYPTORNG);
	
	 /* Init SAM AV3 */
	 status = phhalHw_SamAV3_Init(
		&stHal_SamAv3,
		sizeof ( stHal_SamAv3 ),
		&palCt_DataParams, //?phpalCt_DataParams_t pDataParams <-- isnt this a pal, not bal?
		pHal,
		pKeyStore,
		pCryptoENC,
		pCryptoMAC,
		pCryptoRng,
		NULL,
		NULL,
		PHHAL_HW_SAMAV3_OPMODE_NON_X,
		0x00,
		aTx_SamBuffer,
		sizeof ( aTx_SamBuffer ),
		aRx_SamBuffer,
		sizeof ( aRx_SamBuffer ),
		NULL
		);
	if(status != PH_ERR_SUCCESS) {
		LOG2_ERR("phhalHw_SamAV3_Init fail: %04X", status);
	}
	else {
		LOG2_INF("phhalHw_SamAV3_Init successful!");
	}
//		BSP_Sleep_Ms(10);
	key_store_set_master_key(aAES128Key);
	/* Perform HostAuth with SAM Master Key. */
	status = phhalHw_SamAV3_Cmd_SAM_AuthenticateHost(
				&stHal_SamAv3,
				PHHAL_HW_SAMAV3_CMD_SAM_AUTHENTICATE_HOST_MODE_FULL,
				AES128_KEY_ADDRESS,
				AES128_KEY_VERSION,
				SAM_MASTER_KEY,
				SAM_MASTER_KEY_VERSION
			);
	if(status != PH_ERR_SUCCESS) {
		LOG2_ERR("phhalHw_SamAV3_Cmd_SAM_AuthenticateHost fail: %04X", status);
	}
	else {
		LOG2_INF("phhalHw_SamAV3_Cmd_SAM_AuthenticateHost successful!");
		samav3_state = 1;
	}
	return status;
}

int samav3_init2(void){
	// int input;
	int ret;
    phStatus_t status;
	// input = SEGGER_RTT_WaitKey();
	samav3_ready = 0;
	status = phpalCt_Init();
	if(status != PH_ERR_SUCCESS){
		LOG2_ERR("phpalCt_Init fail: %04X", status);
		return status;
	}
    /** Instance for  CT pal parameter's structure */
	phpalCt_DataParams_t palCt_DataParams ;
    /* The response buffer is used to optimize the code */
	palCt_DataParams.pbAtrBuffer = (uint8_t *)(&aRx_SamBuffer);
	palCt_DataParams.bSizeOfATRbuffer = PH_EXCT7816_MAX_ATR_SIZE;

	/* Activate the card */
	status = phpalCt_ActivateCard(&palCt_DataParams);
	if(PH_ERR_SUCCESS != status){
		LOG2_ERR("Ct Activation fail: %04X", status);
		return status;
	}

	/* Initialize library */
	 /* Set the generic pointer */
	void* pHal = phNfcLib_GetDataParams(PH_COMP_HAL);
	void *pKeyStore = phNfcLib_GetDataParams(PH_COMP_KEYSTORE);
	void * pCryptoENC = phNfcLib_GetDataParams_Extended(PH_COMP_CRYPTOSYM, PH_NFCLIB_COMP_CRYPTOSYM_TYPE_ENC);
	void * pCryptoMAC = phNfcLib_GetDataParams_Extended(PH_COMP_CRYPTOSYM, PH_NFCLIB_COMP_CRYPTOSYM_TYPE_MAC);
	void * pCryptoRng = phNfcLib_GetDataParams(PH_COMP_CRYPTORNG);
	
	 /* Init SAM AV3 */
	 status = phhalHw_SamAV3_Init(
		&stHal_SamAv3,
		sizeof ( stHal_SamAv3 ),
		&palCt_DataParams, //?phpalCt_DataParams_t pDataParams <-- isnt this a pal, not bal?
		pHal,
		pKeyStore,
		pCryptoENC,
		pCryptoMAC,
		pCryptoRng,
		NULL,
		NULL,
		PHHAL_HW_SAMAV3_OPMODE_NON_X,
		0x00,
		aTx_SamBuffer,
		sizeof ( aTx_SamBuffer ),
		aRx_SamBuffer,
		sizeof ( aRx_SamBuffer ),
		NULL
		);


	 if(status == PH_ERR_SUCCESS) {
		LOG2_INF("SAM Init successful!");
	 }
	 else {
		LOG2_ERR("phhalHw_SamAV3_Init fail: %04X", status);
		return status;
	 }

    /* SAM Get Version */
    uint8_t rxLen = 0;
	uint8_t version[64];
    status = phhalHw_SamAV3_Cmd_SAM_GetVersion(
    		&stHal_SamAv3,
			version,
			&rxLen);

    if(status != PH_ERR_SUCCESS) {
		LOG2_ERR("phhalHw_SamAV3_Cmd_SAM_GetVersion fail: %04X", status);
		return status;
    }
    else{
    	 /* Print SAM Version */
    	LOG2_BUF_INF("SAM AV3 Get Version:", version, rxLen);
    }
	if(rxLen < SAM_AV3_GET_VERSION_UID + SAM_AV3_GET_VERSION_UID_LEN) {
        LOG2_ERR("Invalid version data length");        
        return PH_ERR_PARAMETER_OVERFLOW;
    }
	//获取UID
	uint8_t sam_uid[SAM_AV3_GET_VERSION_UID_LEN];
	memcpy(sam_uid, version + SAM_AV3_GET_VERSION_UID, SAM_AV3_GET_VERSION_UID_LEN);
	LOG2_BUF_INF("uid: ", sam_uid, SAM_AV3_GET_VERSION_UID_LEN);
	uint8_t binded = 0;
	ret = config_sam_check_uid(sam_uid, SAM_AV3_GET_VERSION_UID_LEN);
	if(ret < 0){
		LOG2_ERR("config_sam_check_uid fail: %d", ret);
		return ret;
	}
	else{
		if(ret == 1){
			//未绑定
			binded = 0;
		}
		else{
			//已绑定
			binded = 1;
		}
	}
	
	memcpy(samav3_uid, sam_uid, SAM_AV3_GET_VERSION_UID_LEN);
	if(version[SAM_AV3_GET_VERSION_STATE] == SAM_AV3_GET_VERSION_STATE_UNACTIVATED) {
		if(binded){
			//已绑定，不应该没有激活
			return -2;
		}
		//主控密钥为默认密钥
		// input = SEGGER_RTT_WaitKey();
		uint8_t master_key_default[16];
		memset(master_key_default, 0, sizeof(master_key_default));
		ret = key_store_set_master_key(master_key_default);
		if(ret){
			LOG2_ERR("key_store_set_master_key fail: %04X", ret);
			return ret;
		}
		/* Activate SAM AV3 if not yet done */
		status = phhalHw_SamAV3_Cmd_SAM_LockUnlock(
				&stHal_SamAv3,
				PHHAL_HW_SAMAV3_CMD_SAM_LOCK_UNLOCK_TYPE_ACTIVATE_SAM,
				AES128_KEY_ADDRESS,
				AES128_KEY_VERSION,
				SAM_MASTER_KEY,
				SAM_MASTER_KEY_VERSION,
				0,
				0,
				0
		);
		if(status){
			LOG2_ERR("SAM LockUnlock fail: %04X", status);
		}
		else{
			LOG2_INF("SAM LockUnlock successful!");
		}
	}

	//生成主控密钥
	
	uint8_t master_key[16] = {0};
	ret = samav3_generate_master_key(sam_uid, SAM_AV3_GET_VERSION_UID_LEN, master_key);
	if(ret){
		LOG2_ERR("samav3_generate_master_key fail: %d", ret);
		return ret;
	}
	LOG2_BUF_INF("master_key", master_key, 16);
	
	//读取主控密钥信息
	key_entry_read_t key_entry_read;
	uint8_t kid = SAM_MASTER_KEY;
	ret = samav3_get_key_entry(kid, &key_entry_read);
	if(ret){
		LOG2_ERR("samav3_get_key_entry(%d) fail: %d", kid, ret);
		return ret;
	}

	//判断主控密钥是否为默认密钥
	if(key_entry_read.ver[1] == 0x00){
		if(binded){
			//已绑定，不应该是默认密钥
			return -3;
		}
		//主控密钥为默认密钥
		uint8_t master_key_default[16];
		memset(master_key_default, 0, sizeof(master_key_default));
		ret = key_store_set_master_key(master_key_default);
		if(ret){
			LOG2_ERR("key_store_set_master_key fail: %04X", ret);
			return ret;
		}
		//认证默认密钥
		status = phhalHw_SamAV3_Cmd_SAM_AuthenticateHost(
					&stHal_SamAv3,
					PHHAL_HW_SAMAV3_CMD_SAM_AUTHENTICATE_HOST_MODE_FULL,
					AES128_KEY_ADDRESS,
					AES128_KEY_VERSION,
					SAM_MASTER_KEY,
					SAM_MASTER_KEY_VERSION
				);
		if(status != PH_ERR_SUCCESS) {
			LOG2_ERR("AuthenticateHost fail: %04X", status);
			return status;
		}

		//修改主控密钥	
		sam_key_entry_t sam_key_entry = {
			.keys[0] = {0x00,},
			.keys[1] = {0x00,},
			.keys[2] = {0x00,},
			.key_ver[0] = SAM_MASTER_KEY_VERSION,
			.key_ver[1] = 1,
			.key_ver[2] = 2,
			.kce_no = SAM_MASTER_KEY,
			.kce_ver = SAM_MASTER_KEY_VERSION,
			.set = 0x0020,		//AES128
			.ext_set = SAM_KEY_CLASS_HOST,
			.kae_no = 0xFE,
			.kae_ver = 0xFF,
			.kuc_no = 0xFF,
		};
		memcpy(sam_key_entry.keys[0], master_key, 16);		
		// input = SEGGER_RTT_WaitKey();
		status = phhalHw_SamAV3_Cmd_SAM_ChangeKeyEntry(&stHal_SamAv3, kid, 0xFF, (uint8_t*)&sam_key_entry, 0x40);
		if(status){
			LOG2_ERR("phhalHw_SamAV3_Cmd_SAM_ChangeKeyEntry(%d) fail: %d", kid, status);
			return status;
		}
	}
	
	ret = key_store_set_master_key(master_key);	
	if(ret){
		LOG2_ERR("key_store_set_master_key fail: %04X", ret);
		return ret;
	}
	/* Perform HostAuth with SAM Master Key. */
	LOG2_INF("SAM Host Authentication: ");
	status = phhalHw_SamAV3_Cmd_SAM_AuthenticateHost(
				&stHal_SamAv3,
				PHHAL_HW_SAMAV3_CMD_SAM_AUTHENTICATE_HOST_MODE_FULL,
				AES128_KEY_ADDRESS,
				AES128_KEY_VERSION,
				SAM_MASTER_KEY,
				SAM_MASTER_KEY_VERSION
			);
	if(status != PH_ERR_SUCCESS) {
		if(binded){
			//已绑定，不应该是默认密钥
			return -3;
		}		
		LOG2_PRINT("fail: %04X", status);
		//主控密钥为默认密钥
		uint8_t master_key_default[16];
		memset(master_key_default, 0, sizeof(master_key_default));
		ret = key_store_set_master_key(master_key_default);
		if(ret){
			LOG2_ERR("key_store_set_master_key fail: %04X", ret);
			return ret;
		}
		//认证默认密钥
		status = phhalHw_SamAV3_Cmd_SAM_AuthenticateHost(
					&stHal_SamAv3,
					PHHAL_HW_SAMAV3_CMD_SAM_AUTHENTICATE_HOST_MODE_FULL,
					AES128_KEY_ADDRESS,
					AES128_KEY_VERSION,
					SAM_MASTER_KEY,
					SAM_MASTER_KEY_VERSION
				);
		if(status != PH_ERR_SUCCESS) {
			LOG2_ERR("AuthenticateHost fail: %04X", status);
			return status;
		}

		//修改主控密钥	
		sam_key_entry_t sam_key_entry = {
			.keys[0] = {0x00,},
			.keys[1] = {0x00,},
			.keys[2] = {0x00,},
			.key_ver[0] = SAM_MASTER_KEY_VERSION,
			.key_ver[1] = 1,
			.key_ver[2] = 2,
			.kce_no = SAM_MASTER_KEY,
			.kce_ver = SAM_MASTER_KEY_VERSION,
			.set = 0x0020,		//AES128
			.ext_set = SAM_KEY_CLASS_HOST,
			.kae_no = 0xFE,
			.kae_ver = 0xFF,
			.kuc_no = 0xFF,
		};
		memcpy(sam_key_entry.keys[0], master_key, 16);
		// input = SEGGER_RTT_WaitKey();
		status = phhalHw_SamAV3_Cmd_SAM_ChangeKeyEntry(&stHal_SamAv3, kid, 0xFF, (uint8_t*)&sam_key_entry, 0x40);
		if(status){
			LOG2_ERR("phhalHw_SamAV3_Cmd_SAM_ChangeKeyEntry(%d) fail: %d", kid, status);
			return status;
		}
		//装载认证新密钥
		ret = key_store_set_master_key(master_key);	
		if(ret){
			LOG2_ERR("key_store_set_master_key fail: %04X", ret);
			return ret;
		}
		LOG2_INF("SAM Host Authentication: ");
		status = phhalHw_SamAV3_Cmd_SAM_AuthenticateHost(
					&stHal_SamAv3,
					PHHAL_HW_SAMAV3_CMD_SAM_AUTHENTICATE_HOST_MODE_FULL,
					AES128_KEY_ADDRESS,
					AES128_KEY_VERSION,
					SAM_MASTER_KEY,
					SAM_MASTER_KEY_VERSION
				);
	}

	if(status == PH_ERR_SUCCESS) {
		LOG2_PRINT("successful!");
		memcpy(aAES128Key, master_key, sizeof(aAES128Key));
		if(!binded){
			//未绑定
			config_sam_set_uid(sam_uid, SAM_AV3_GET_VERSION_UID_LEN);
		}
		samav3_ready = 1;
		samav3_state = 1;
	}
	return status;
}

void samav3_get_uid(uint8_t* uid, uint8_t *uid_len){
	memcpy(uid, samav3_uid, SAM_AV3_GET_VERSION_UID_LEN);
	if(uid_len){
		*uid_len = SAM_AV3_GET_VERSION_UID_LEN;
	}
}

int samav3_is_ready(void){
	return samav3_ready;
}

int samav3_is_active(void){
	return samav3_state;
}

/***********************************************************************************************
*                            End Of File
**********************************************************************************************/

